// Phong-Blinn shading model fragment shader

#define ONE_OVER_PI 0.3183098861928886

uniform sampler2D specularMap;

uniform float fScattering;
uniform float fHeightScale;

varying vec2 Texcoord;
varying vec3 ViewDirection;
varying vec3 LightDirection;
varying float Distance;

vec2 fvGetCorrectSamplingPosition(vec2 texCoord, vec3 view)
{
   const int numStepsLinear = 16;
   const int numStepsBinary = 10;
   
   vec3 position = vec3(texCoord, 0.0);
   
   view.xy *= view.z;
   view.xy *= fHeightScale;
   
   int i;
   for (i = 0; i < numStepsLinear; ++i)
   {
      vec4 tex = texture2D(bumpMap, position.xy);
      if (position.z < tex.w) position += view;      
      else i = numStepsLinear;
   }
   
   for (i = 0; i < numStepsBinary; ++i)
   {
      view *= 0.5;
      vec4 tex = texture2D(bumpMap, position.xy);
      if (position.z < tex.w) position += view;
      else position -= view;
   }
   
   return position.xy;
}

vec4 fvGetPhongBlinnIllumination(vec2 texCoord, bool notSelfShadowed)
{
   vec3 fvLightDirection = normalize( LightDirection );
   vec3 fvViewDirection = normalize( ViewDirection );
   vec3 fvHalf = normalize( fvLightDirection + fvViewDirection );
   
   vec3 fvNormal = FS_GET_NORMAL(texCoord);
   
   fvNormal.y = -fvNormal.y;   
   
   float fNDotL = max ( 0.0, dot( fvNormal, fvLightDirection ) );
   float fNDotH = max ( 0.0, dot( fvNormal, fvHalf ) );

   vec4 fvTotalDiffuse = gl_LightSource[0].diffuse * fNDotL;
   vec4 fvTotalSpecular = gl_LightSource[0].specular * ( pow( fNDotH, gl_FrontMaterial.shininess ) ) * texture2D( specularMap, texCoord );
   
   float fAttenuation = 1.0 / (gl_LightSource[0].constantAttenuation +
                               gl_LightSource[0].linearAttenuation * Distance +
                               gl_LightSource[0].quadraticAttenuation * Distance * Distance);
   
   if ( !notSelfShadowed && fNDotL != 0.0 ) fvTotalDiffuse = fvShadowColor * (1.0 - fNDotL);
   
   fvTotalSpecular *= (2.0 + gl_FrontMaterial.shininess) * (0.5 * ONE_OVER_PI);//(1.0 + gl_FrontMaterial.shininess) * 0.5;
   fvTotalDiffuse *= ONE_OVER_PI;
      
   return (/*fvTotalDiffuse +*/ fvTotalSpecular) * fAttenuation;
}

vec4 fvGetSubsurfaceScatterIllumination(vec2 texCoord)
{
   vec3 fvLightDirection = normalize( LightDirection );   
   vec3 fvNormal = FS_GET_NORMAL(texCoord);   
   vec4 fvTotalDiffuse = gl_LightSource[0].diffuse;
   float fDiffuse = 0.0;
   const float c_maxNumber = 4.0;
   const float c_step = 1.0;
   float sum = 0.0;
   
   for (float y = -c_maxNumber; y < c_maxNumber; y += c_step)
   {
      for (float x = -c_maxNumber; x < c_maxNumber; x += c_step)
      {
         float fX = x / (2.0 * c_maxNumber);
         float fY = y / (2.0 * c_maxNumber);
         vec3 fvNorm = FS_GET_NORMAL(texCoord + vec2(fX, fY) * fScattering / 25.0);
         
         fvNorm.y = -fvNorm.y;
         
         vec3 fvLight = normalize(fvLightDirection + vec3(fX, fY, 0.0) * fScattering / 25.0);
         fDiffuse += max( 0.0, dot(fvNorm, fvLight) );
         sum++;
      }
   }
   
   float fAttenuation = 1.0 / (gl_LightSource[0].constantAttenuation +
                               gl_LightSource[0].linearAttenuation * Distance +
                               gl_LightSource[0].quadraticAttenuation * Distance * Distance);
   
   fDiffuse /= sum;
   fvTotalDiffuse *= (ONE_OVER_PI * fDiffuse);
      
   return fvTotalDiffuse * fAttenuation;
}
